/*
 * @Description: 定义蛇类
 * @Author: Zhy
 * @Date: 2024-07-09 10:47:34
 * @LastEditTime: 2024-07-09 16:49:07
 * @LastEditors: Zhy
 */
export default class Snake {
  el: HTMLElement; /* 蛇的元素（容器） */
  head: HTMLElement;
  bodies: HTMLCollection; /* 蛇的身体，包括头部 */

  constructor() {
    this.el = document.getElementsByClassName("snake")[0] as HTMLElement;
    this.head = document.getElementsByClassName("snake-head")[0] as HTMLElement;
    this.bodies = this.el.getElementsByTagName("div") as HTMLCollection;
  }

  // 获取蛇的坐标（蛇头坐标）
  get x() {
    return this.head.offsetLeft;
  }
  get y() {
    return this.head.offsetTop;
  }

  set x(value: number) {
    if (this.x === value) return;
    // 当蛇头与蛇头后的一节身体在水平方向重合时，判定为水平方向掉头
    if (
      this.bodies[1] &&
      (this.bodies[1] as HTMLElement).offsetLeft === value
    ) {
      value = value > this.x ? this.x - 10 : this.x + 10;
    }

    this.moveSnake();
    this.head.style.left = value + "px";

    if (value < 0 || value > 290) {
      throw new Error("蛇撞墙了！");
    }
    this.checkHeadBody();
  }
  set y(value: number) {
    if (this.y === value) return;
    // 当蛇头与蛇头后的一节身体在竖直方向重合时，判定为竖直方向掉头
    if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
      value = value > this.y ? this.y - 10 : this.y + 10;
    }

    this.moveSnake();
    this.head.style.top = value + "px";

    if (value < 0 || value > 290) {
      throw new Error("蛇撞墙了！");
    }
    this.checkHeadBody();
  }

  // 蛇增加身体的方法
  addBody() {
    this.el.appendChild(document.createElement("div"));
  }

  // 添加蛇身体移动的方法
  // 蛇身体每节在移动后都与前一节移动前重合，因此需要从后往前依次修改每一节的身体坐标
  moveSnake() {
    for (let i = this.bodies.length - 1; i > 0; i--) {
      // 前一节的坐标
      const prevX = (this.bodies[i - 1] as HTMLElement).offsetLeft;
      const prevY = (this.bodies[i - 1] as HTMLElement).offsetTop;

      // 修改当前节的坐标，使其与前一节移动前的坐标重合
      (this.bodies[i] as HTMLElement).style.left = prevX + "px";
      (this.bodies[i] as HTMLElement).style.top = prevY + "px";
    }
  }

  // 检查蛇头是否撞向身体
  checkHeadBody() {
    for (let i = 1; i < this.bodies.length; i++) {
      if (
        this.x === (this.bodies[i] as HTMLElement).offsetLeft &&
        this.y === (this.bodies[i] as HTMLElement).offsetTop
      ) {
        throw new Error("蛇头撞到身体了！");
      }
    }
  }
}
